#ifndef TBS_CPP_MATH
#define TBS_CPP_MATH

#include <base/base.hpp>
#include <deque>

namespace tbs::math {
class MathContext {
 public:
  /**
   * 读取byte
   * @param v 读取的值
   * @return 若存在byte返回值无效
   */
  virtual char readByte(CONST char &v) CONST = 0;

  // 定义符号常量
  static CONST int SIGN_POSITIVE = 1, SIGN_NEGATIVE = -1, SIGN_DECIMAL = -2, SIGN_NUMBER = 0, SIGN_ERROR = -3;

  /**
   * 读取char
   * @param v 读取的值
   * @param sign 符号位 0 不是符号;1 正号 ;-1 负号,-2 小数点;
   * @return 若存在符号位返回值无效
   */
  virtual char readChar(CONST char &v, int &sign) CONST = 0;

  // 获取数值基数
  virtual int getBase() CONST = 0;
};

class TenBaseContext : public virtual MathContext {
 public:
  // 十进制上下文中读取byte
  virtual char readByte(const char &v) const override;

  // 十进制上下文中读取char
  virtual char readChar(const char &v, int &sign) const override;

  // 十进制上下文获取基数
  virtual int getBase() const override;
};

class BinaryContext : public virtual MathContext {
 public:
  // 二进制上下文中读取byte
  virtual char readByte(const char &v) const override;

  // 二进制上下文中读取char
  virtual char readChar(const char &v, int &sign) const override;

  // 二进制上下文获取基数
  virtual int getBase() const override;
};

// 全局数学上下文实例
static MathContext *TenMathContext = new TenBaseContext();
static MathContext *BinaryMathContext = new BinaryContext();

class Decimal {
 private:
  using BitArray = std::deque<char>;

  BitArray _integers;
  mutable int _scale = 0;
  int positiveAndNegativeMarkings = 0;
  MathContext *_context = nullptr;

  /**
   * 通过字符串初始化Decimal对象
   * @param obj 要初始化的Decimal对象
   * @param v 初始化的字符串值
   */
  static void initByStr(Decimal &obj, CONST char *v);

 protected:

  using op_func = std::function<
      bool(char
           &v,
           CONST int &i
      )>;
  enum PartOfDecimal {
    INTEGER, DECIMAL
  };
  void operateInAvaliable(op_func func, CONST PartOfDecimal &part = INTEGER);

  void operateAll(op_func f, CONST PartOfDecimal &part = INTEGER);
 public:

  /**
   * @brief 返回值bool 是否继续遍历，第一个参数CHAR 为当前遍历的字符，第二个参数INT 为当前字符的索引(从小数点开始算，如123.456，3和4分别在整数部分第0位和小数部分第0位)
   */
  using seek_func = std::function<bool(CONST char &, CONST int &)>;

  using magic_func = std::function<void(CONST Decimal &)>;

  /**
   * @brief 保留整数位
   * @param obj
   * @return
   */
  static Decimal toInteger(CONST Decimal &obj);

  /**
   * @brief 保留小数作为整数
   * @param obj
   * @return
   */
  static Decimal decimalAsInteger(CONST Decimal &obj);

  /**
   * @brief 有效小数位数
   * @return
   */
  int avaliableAccuracy() const;

  /**
   * @brief  有效整数位数
   * @return
   */
  int availableScale() const;

  /**
   * @brief 移动小数点，向左移动v位，若v为负数，则向右移动v位
   * @param v
   */
  void moveDecimal(int v);

  // 各种类型构造函数
  Decimal(double);

  Decimal(float);

  Decimal(int);

  Decimal(long);

  Decimal(unsigned long);

  Decimal(unsigned int);

  Decimal(CONST Decimal &);

  Decimal(Decimal &&) noexcept;
  Decimal(tbs::str_type);

  /**
   * @brief   从字符串初始化Decimal对象
   * @param v 要初始化的字符串值
   * @param m   MathContext对象，用于解析字符串，默认为十进制上下文
   */
  Decimal(CONST char *v = "0", MathContext *m = TenMathContext);

  /**
  * 比较两个Decimal对象
  * @param a 第一个Decimal对象
  * @param b 第二个Decimal对象
  * @return 比较结果，-1表示a小于b，0表示a等于b，1表示a大于b
  */
  static int compare(CONST Decimal &a, CONST Decimal &b);

  /**
   *  比较两个Decimal对象，不考虑正负号
   * @param a   第一个Decimal对象
   * @param b   第二个Decimal对象
   * @return 比较结果，-1表示a小于b，0表示a等于b，1表示a大于b
   */
  static int absCompare(const Decimal &a, const Decimal &b);

  /**
   * @brief 获取整数部分的第index位
   * @param index 位置，从个位开始（小数点前第index位）
   * @return
   */
  int seekBitFromIntegers(const int &index) const;

  /**
   * @brief 获取小数部分的第index位
   * @param index 位置，从个位开始（小数点后第index位）
   * @return
   */
  int seekBitFromDecimals(const int &index) const;

  /**
   * @brief 设置整数部分的第index位
   * @param index 位置，从个位开始（小数点前第index位）
   * @param v 要设置的值
   */
  void setBitFromIntegers(const int &index, const char &v);

  void operateFromIntegersAt(const int &index, op_func func);

  void operateFromDecimalsAt(const int &index, op_func func);

  void seekFromInteger(seek_func sf, CONST bool &isAll = false) CONST;

  void seekFromDecimal(seek_func sf, CONST bool &isAll = false) CONST;

  /**
   * @brief 设置小数部分的第index位
   * @param index 位置，从个位开始（小数点后第index位）
   * @param v 要设置的值
   */
  void setBitFromDecimals(const int &index, const char &v);

  /**
   * 检查是否为负数
   * @return 是否是负数
   */
  bool isNegative() CONST;

  /**
   * 转换为正数
   */
  void toPositive();

  /**
   * 转换为负数
   */
  void toNegative();

  /**
   * 反转正负号
   */
  void reverse();

  /**
   * 设置小数部分的位数
   * @param v 小数部分的位数
   */
  void accuracy(int v);

  /**
   * 小数部分的位数
   * @return 小数部分的位数
   */
  int accuracy() CONST;

  /**
   * @brief   整数部分的位数
   * @return
   */
  int scale() CONST;

  /**
   * 设置整数部分的位数
   * @param v 整数部分的位数
   */
  void scale(int v);

  // 比较运算符重载
  bool operator==(CR_NONE_NAME(Decimal)) CONST;

  bool operator!=(CR_NONE_NAME(Decimal)other) CONST {
    return !(*this == other);
  }

  bool operator<(CR_NONE_NAME(Decimal)) CONST;

  bool operator>(CR_NONE_NAME(Decimal)) CONST;

  // 赋值运算符重载
  Decimal &operator=(CR_NONE_NAME(Decimal));

  Decimal &operator=(CR_NONE_NAME(float));

  Decimal &operator=(CR_NONE_NAME(double));

  Decimal &operator=(CR_NONE_NAME(long));

  Decimal &operator=(CR_NONE_NAME(unsigned long));

  Decimal &operator=(CR_NONE_NAME(unsigned int));

  Decimal &operator=(CR_NONE_NAME(tbs::str_type));

  Decimal &operator=(Decimal &&) noexcept;

  // 算术运算符重载
  Decimal operator+(CR_NONE_NAME(Decimal)) CONST;

  Decimal &operator+=(CR_NONE_NAME(Decimal));
  Decimal &operator-=(CR_NONE_NAME(Decimal));
  Decimal &operator*=(CR_NONE_NAME(Decimal));
  Decimal &operator/=(CR_NONE_NAME(Decimal));

  Decimal operator-(CR_NONE_NAME(Decimal)) CONST;

  Decimal operator*(CR_NONE_NAME(Decimal)) CONST;

  Decimal operator/(CR_NONE_NAME(Decimal)) CONST;

  explicit operator const char *() {
    return toString().c_str();
  }

  /**
   * 转换为字符串
   * @return 表示Decimal对象的字符串
   */
  tbs::str_type toString() CONST;

  /**
   * 模拟小数点移动
   * @param v
   */
  void magicallyMoveDecimal(CONST int &v, magic_func fc) CONST;

};

}

#endif